/*!

# Caret jQuery Plugin
+ Version: 0.1.0.0
+ Copyright © 2013 [Syue](mailtot:syuemingfang@gmail.com). All rights reserved.
+ Date: *Thu Aug 29 2013 11:16:29 GMT+0800 (Central Standard Time)*

****************************************************************************************************/

/*!

## How to Use
 1. **Setup** include this javascript files in your header.   
  `<script src='caret.js'><\/script>`

 3. **Set**
  `$(yourDOM)()`

****************************************************************************************************/
;(function($){
 $.fn.caret=function(options){
  var default_set={
    //!## Options
   version: '0.1.0.0',
   on: 'click',  //+ **on**
   wrap: 'off',  //+ **wrap**
   target: null  //+ **target**
  }
  var set=$.extend(default_set, options);
  return this.each(
    function(){initialize($(this), set)}
  );
  //!## API
  function getPos(obj){
    //!+ Get Position
    // Declare
    var text=obj.val();
    var arr=text.split('');
    var w=0;
    var n=0;
    var end=0;
    var full=1; //Full Char
    var half=0.65; //Half Char
    // Constructor
    // Get Line Break
    for(var i=0; i < getCaret.call(this, {obj: obj[0]}); i++){
      if(arr[i]=="\n"){
        end=i+1;
        n++;
      }
    }
    // Get Line Width
    for(var i=end; i < getCaret.call(this, {obj: obj[0]}); i++){
      for(var j=0; j < arr[i].length; j++){
        var c=arr[i].charCodeAt(j);
        if(!(c >= 32 && c <= 126)) w=w+full;
        else w=w+half
      }
    }
    var o={
      cursor: {
        all: getCaret.call(this, {obj: obj[0]}),
        line: w
      },
      font: getVal.call(this, {obj: obj.css('font-size')}),
      lineheight: getVal.call(this, {obj: obj.css('line-height'), def: obj.css('font-size')}),
      left:obj.offset().left,
      top:obj.offset().top,
      space: getVal.call(this, {obj: obj.css('letter-spacing'), def: obj.css('font-size')}),
      paddingLeft: getVal.call(this, {obj: obj.css('padding-left')}),
      paddingTop: getVal.call(this, {obj: obj.css('padding-top')})
    }
    var unit=o.font.unit;
    var x=Number(o.paddingTop.val+o.top-obj.scrollTop()+(n*o.lineheight.val))+unit;
    var y=Number(o.paddingLeft.val+o.left-obj.scrollLeft()+((o.font.val+o.space.val)*o.cursor.line))+unit;
    return {x: x, y: y}
  }
  //!## Function
  function initialize(that, set){
    //!+ **initialize(that, set)**
    // Declare
    set.wrap != 'auto' ? that[0].setAttribute('wrap', set.wrap) : '';
    // Constructor
    that.on(set.on, function(){
      var pos=getPos(that, set);
      setPos.call(this, {obj: set.target, pos: pos});
    });
  }
  function setPos(){
    //!+ **setPos()** Set Position
    //!  **obj** **pos**
    // Declare
    var opt=arguments[0];
    // Constructor
    $(opt.obj).css('top', opt.pos.x);
    $(opt.obj).css('left', opt.pos.y);
  } 
  function getCaret(){
    //!+ **getCaret()** Get Caret
    //!  **obj**
    // Declare
    var opt=arguments[0];
    if(opt.obj.selectionStart){
      // Chrome, Firefox
      return opt.obj.selectionStart;
    } else if(!document.selection){
      return 0;
    } else{
      // IE 
      var c='\001';
      var sel=document.selection.createRange();
      var dul=sel.duplicate();
      var len=0;
      dul.moveToElementText(opt.obj);
      sel.text=c;
      var d=dul.text.replace(/\n/g, '');
      len=d.indexOf(c);
      sel.moveStart('character', -1);
      sel.text='';
      return len;     
    }
  }
  function getVal(){
    //!+ **getVal()** Get Value
    //!  **str** **def**
    // Declare
    var opt=arguments[0];
    var modifiers='ig';
    var r={}; //Result
    var obj={};
    var def={}; //Default Object
    var pattern={
      1: new RegExp("[^0-9\.]*", modifiers),
      2: new RegExp("[^a-z]*", modifiers)
    }
    // Constructor
    if(opt.obj){
      obj={
        val: Number(opt.obj.replace(pattern[1], '')),
        unit: opt.obj.replace(pattern[2], '')
      }
    }
    if(opt.def){
      def={
         val: Number(opt.def.replace(pattern[1], ''))*1.2,
        unit: opt.def.replace(pattern[2], '')         
      }          
    }
    if(opt.obj){
      if(obj.val == ''){
        if(opt.obj == 'normal'){
          r=def;
        } 
      } else{
        if(obj.unit == ''){
          obj={
            val: Number(opt.obj.replace(pattern[1], ''))*obj.obj,
            unit: opt.obj.replace(pattern[2], '')
          }
        }         
          r=obj;
      }      
    }
    if(typeof r.val == 'undefined') r={val: 0, unit: 'px'};
    return r;
  }
 }
})(jQuery);